<?php

class s
{

  /**
   * @var Config
   */
  protected static $config;

  /**
   * @var ApplicationController
   */
  protected static $application;

  /**
   * @var Request
   */
  protected static $request;

  /**
   * @var Router
   */
  protected static $router;

  /**
   * @var array
   */
  protected static $handlers;

  /**
   * @var array
   */
  protected static $actions;

  /**
   *
   * @return ApplicationController
   */
  public static function getInstance()
  {
    if (empty(self::$application)) {
      self::$application = new ApplicationControllerImpl();

      set_exception_handler(array('s', 'exceptionHandler'));
    }

    return self::$application;
  }

  /**
   *
   * @return Config
   */
  public static function config()
  {
    if (empty(self::$config)) {
      self::$config = new Config();
    }

    return self::$config;
  }

  /**
   *
   * @return Request
   */
  public static function request()
  {
    if (empty(self::$request)) {
      self::$request = new Request();
    }

    return self::$request;
  }

  /**
   *
   * @return Router
   */
  public static function router()
  {
    if (empty(self::$router)) {
      self::$router = new Router();
    }

    return self::$router;
  }

  /**
   *
   * @return Response
   */
  public static function response()
  {
    return self::getInstance()->response();
  }

  public static function makeUrl($route = null, $get = array(), $remove = array())
  {
    return self::response()->makeUrl($route, $get, $remove);
  }

  /**
   *
   * @param string $hook hook name
   * @param function $callback valid php callback
   * @param ... extra parameters
   */
  public static function addAction($hook, $callback)
  {
    $args = array_slice(func_get_args(), 2);
    self::$actions[$hook][] = array($callback, $args);
  }

  /**
   *
   * @param string $hook hook name
   */
  public static function callAction($hook)
  {
    if (isset(self::$actions[$hook])) {
      $_args = array_slice(func_get_args(), 1);

      foreach (self::$actions[$hook] as $action) {
        $args = array_merge($action[1], $_args);
        call_user_func_array($action[0], $args);
      }
    }
  }

  /**
   * Set a callback to handle specific exceptions
   *
   * @param string $type exception class
   * @param function $callback valid php callback
   * @param integer $code exception code. optional.
   */
  public static function setExceptionHandler($type, $callback, $code = null)
  {
    if (empty($code)) {
      $code = 0;
    }

    self::$handlers[$type][$code] = $callback;

    if ($code && ! isset(self::$handlers[$type][0])) {
      self::$handlers[$type][0] = $callback;
    }
  }

  /**
   *
   * @param Exception $exception
   */
  public static function exceptionHandler(Exception $exception)
  {
    $type = get_class($exception);
    $code = $exception->getCode();

    if (! isset(self::$handlers[$type][$code])) {
      $code = 0;
    }

    if (isset(self::$handlers[$type][$code])) {
      return call_user_func(self::$handlers[$type][$code]);
    }

    sy_exception_handler($exception);
  }

}
